package com.ruoyi.livesass.api.sync;

import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cyl.manager.act.domain.entity.CouponActivity;
import com.cyl.manager.act.mapper.CouponActivityMapper;
import com.cyl.manager.act.service.CouponActivityNewService;
import com.cyl.manager.lbs.domain.LbsZbjl;
import com.cyl.manager.lbs.mapper.LbsZbjlMapper;
import com.cyl.manager.lbs.service.LbsZbjlService;
import com.cyl.manager.ums.domain.entity.Member;
import com.cyl.manager.ums.mapper.MemberMapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.livesass.LiveVideoService;
import com.ruoyi.livesass.api.domain.LbsGkscDay;
import com.ruoyi.livesass.api.mapper.LbsGkscDayMapper;
import com.ruoyi.livesass.api.service.LbsGkscDayService;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.domain.SysOperLog;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.impl.SysDeptServiceImpl;
import com.volcengine.model.livesaas.response.GetActivityAPIResponse;
import com.volcengine.model.livesaas.response.GetActivityAPIResponse.GetActivityAPIBody;
import com.volcengine.model.livesaas.response.GetUserBehaviorListResponseAPIV2;
import com.volcengine.model.livesaas.response.GetUserBehaviorListResponseAPIV2.UserBehaviorV2;
import com.volcengine.model.livesaas.response.ListActivityAPIResponse;
import com.volcengine.model.livesaas.response.ListActivityAPIResponse.ListActivityAPIForm;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.StrUtil;

/**
 * @ClassName: LiveUserTimeDataToDaySynService
 * @Description: TODO(直播用户观看时长-每日入库)
 * @author 晏大兵
 * @date 2025年2月10日 上午11:13:23
 */
@Component("gkscDaySyn")
@Order(3)
public class LiveUserTimeDataToDaySynService implements ApplicationRunner {

	private static final Logger LOG = LoggerFactory.getLogger(LiveUserTimeDataToDaySynService.class);

	@Autowired
	LiveVideoService liveVideoService;

	@Autowired
	LbsGkscDayMapper lbsGkscDayMapper;

	@Autowired
	LbsGkscDayService lbsGkscDayService;
	
	@Autowired
	LbsZbjlService lbsZbjlService;
	
    @Autowired
    LbsZbjlMapper lbsZbjlMapper;

	@Autowired
	MemberMapper memberMapper;

	@Autowired
	private RedisCache redisCache;

	@Autowired
	private ISysConfigService configService;
	
	@Autowired
	SysDeptServiceImpl sysDeptServiceImpl;
	
	@Autowired
	CouponActivityMapper couponActivityMapper;
	
	@Autowired
	CouponActivityNewService couponActivityNewService;

	//@Value("${custom.hsSubUserName}")
	//private String hsSubUserName;
	
	@Value("${custom.synTaskEnable}")
	private boolean synTaskEnable;
	
	Map<String, JSONObject> repeatSubUserName = Maps.newHashMap();
	

	private String synCacheKey = "userTimeDataSynState";
	
	
	

	@Override
	public void run(ApplicationArguments args) throws Exception {
		try {
			/*
			if(!redisCache.hasKey(synCacheKey)) {
				return ;
			}
			
			
			String synState = redisCache.getCacheObject(synCacheKey);
			
			// 结束同步
			if (null != synState && !StrUtil.isBlankIfStr(synState) && "start".equals(synState)) {
				activityStartPorcess();
			}*/
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 这里用于每日凌晨跑一次遗漏数据
	//@Scheduled(cron = "${custom.synTasks.liveUserTimeToDayTask}")
	public void performTask() throws Exception {
		if (!synTaskEnable) {
			return;
		}

		LOG.error("直播用户观看时长-每日入库开始 ：" + System.currentTimeMillis());

		try {
			
			this.syncLoadSysConfig(true);
			
		} catch (Exception e) {
			e.printStackTrace();
			LOG.error("定时任务异常 | 重新执行");
			Thread.sleep(2000);
			performTask();
		}

		LOG.error("直播用户观看时长-每日入库结束 ：" + System.currentTimeMillis());
	}

	/**
	 * @Title: activityStartPorcess
	 * @Description: TODO(一旦有直播间开始直播后会回调此方法)
	 * @param 设定文件
	 * @return void 返回类型
	 * @throws
	 
	public void activityStartPorcess() {  //TODO 此功能目前已经废弃
		LOG.error("直播回调开始");
		redisCache.setCacheObject(synCacheKey, "start");
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					String synState = redisCache.getCacheObject(synCacheKey);
					try{
						syncLoadSysConfig(false);
						Thread.sleep(120000);
					}catch(Exception e) {
						e.printStackTrace();
					}
					
					// 结束同步
					if (null == synState || StrUtil.isBlankIfStr(synState) || "stop".equals(synState)) {
						break;
					}
				}
			}
		}).start();
	}
	*/
	
	
	
	/**
	* @Title: activityStopPorcess 
	* @Description: TODO(直播结束后回调此方法) 
	* @param     设定文件 
	* @return void    返回类型 
	 * @throws Exception 
	 * @throws NumberFormatException 
	* @throws
	 */
	public void activityStopPorcess() throws Exception {
		
		if(redisCache.hasKey(synCacheKey)) {
			String syuState = redisCache.getCacheObject(synCacheKey);
			if("start".equals(syuState)) {
				System.out.println("直播时长同步取消-已经有任务在进行中了！");
				return ;
			}
		}
		
		redisCache.setCacheObject(synCacheKey, "start");
		
		LOG.error("回调 - 直播停止 | 延迟5分钟开始获取用户观看数据");
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(300000); //如果直播结束 延迟5分钟后才停止同步
					//redisCache.setCacheObject(synCacheKey, "stop");
					syncLoadSysConfig(false);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
	}
	
	
	/**
	* @Title: activityStopPorcess 
	* @Description: TODO(直播结束后回调此方法) 
	* @param     设定文件 
	* @return void    返回类型 
	 * @throws Exception 
	 * @throws NumberFormatException 
	* @throws
	 */
	public void activityStopPorcess(String ActivityID) throws Exception {
		
		//TODO 根据单一直播间进行观看时长同步
		
		LOG.error("回调 - 直播停止 | 延迟5分钟开始获取用户观看数据");
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(300000); //如果直播结束 延迟5分钟后才停止同步
					GetActivityAPIResponse activityAPIResponse = liveVideoService.getActivityInfo(Long.valueOf(ActivityID));
					GetActivityAPIBody getActivityAPIBody = activityAPIResponse.getResult();
					//LbsZbjl  lbsZbjl  = lbsZbjlMapper.selectById(ActivityID);
					DateTime now = DateTime.now();
					String gsrq = now.toDateStr();
					
					ListActivityAPIForm listActivityAPIForm = new ListActivityAPIForm();
					
					listActivityAPIForm.setLiveTime(getActivityAPIBody.getLiveTime());
					listActivityAPIForm.setName(getActivityAPIBody.getName());
					listActivityAPIForm.setId(getActivityAPIBody.getId());
					listActivityAPIForm.setStatus(getActivityAPIBody.getStatus());
					
					List<ListActivityAPIForm> offsetDayListActivity = Lists.newArrayList();
					offsetDayListActivity.add(listActivityAPIForm);
					
					
					LOG.error("直播停止 | 已经延迟5分钟 开始同步观看数据   直播间名称["+getActivityAPIBody.getName()+"],直播间ID["+ActivityID+"]");
					
					processToDay(offsetDayListActivity, gsrq);
					
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
	}
	
	
	/**
	 * 
	* @Title: syncLoadSysConfig 
	* @Description: TODO(这个是用于每日定时同步) 
	* @param @param isOffsetDay
	* @param @throws Exception    设定文件 
	* @return void    返回类型 
	* @throws
	 */
	public void syncLoadSysConfig(boolean isOffsetDay) throws Exception {
		SysConfig sysConfig = configService.selectConfigByKey2("sys_config");
		if (null != sysConfig && !StrUtil.isBlankIfStr(sysConfig.getRemark())) {
			JSONObject sysConfigJsonObject = JSONObject.parseObject(sysConfig.getRemark());
			if (sysConfigJsonObject.containsKey("activityConfig")) {
				JSONArray activityConfigList = sysConfigJsonObject.getJSONArray("activityConfig");
				
				/**/
				for (int i = 0; i < activityConfigList.size(); i++) { //去重subusername
					JSONObject item = activityConfigList.getJSONObject(i);
					repeatSubUserName.put(item.getString("subusername"), item);
				}
				
				for(String sunName : repeatSubUserName.keySet()) {
					this.syncLiveUserTimeDataToDay(sunName, isOffsetDay);
				}
				
				/*
				for (int i = 0; i < activityConfigList.size(); i++) {
					JSONObject item = activityConfigList.getJSONObject(i);
					this.syncLiveUserTimeDataToDay(item.getString("subusername"), isOffsetDay);
				}
				*/
				
				
			}
		}
		redisCache.deleteObject(synCacheKey);
	}
	
	

	/**
	 * @Title: syncLiveVideoFlows
	 * @Description: TODO(同步直播流量数据)
	 * @param 设定文件
	 * @return void 返回类型
	 * @throws Exception
	 * @throws
	 */
	public void syncLiveUserTimeDataToDay(String userName, boolean isOffsetDay) throws Exception {

		// 首先查询出需要统计的直播间
		DateTime now = DateTime.now();
		String nowDayStr = now.toDateStr();
		DateTime nowDayTime = DateTime.of(nowDayStr, "yyyy-MM-dd");
		int pageNo = 1;
		int pageItemCount = 10000;
		int status = 0; // 已结束的直播间
		String sortBy = "LiveTime";
		String sortOrder = "Desc";

		// 更新当天时长数据
		String gsrq;
		long toDayTime;
		if(isOffsetDay) {
			DateTime offsetDay = now.offset(DateField.DAY_OF_YEAR, -1);
			gsrq = offsetDay.toDateStr();
			toDayTime = (offsetDay.toJdkDate().getTime() / 1000);
		}else {
			gsrq = nowDayTime.toDateStr();
			toDayTime = (nowDayTime.toJdkDate().getTime() / 1000);
		}
		
		ListActivityAPIResponse offsetDayListActivityAPIResponse = liveVideoService.listActivity(pageNo, pageItemCount, userName, status, sortBy, sortOrder, toDayTime);
		List<ListActivityAPIForm> offsetDayListActivity = offsetDayListActivityAPIResponse.getResult().getActivities();
		
		LOG.error("所需同步的直播间subname["+userName+"]liveTime["+toDayTime+"] | " + JSONObject.toJSONString(offsetDayListActivity));
		
		processToDay(offsetDayListActivity, gsrq);
	}

	/**
	 * @Title: processOffsetDay
	 * @Description: TODO(根据返回的直播间进行循环查询合并观看时长)
	 * @param @param offsetMonthListActivity 设定文件
	 * @return void 返回类型
	 * @throws Exception
	 * @throws
	 */
	private void processToDay(List<ListActivityAPIForm> offsetMonthListActivity, String gsrq) throws Exception {

		for (ListActivityAPIForm item : offsetMonthListActivity) {
			
			LOG.error("开始同步按天统计用户观看时长.");
			Map<String, LbsGkscDay> userGkscMap = Maps.newHashMap();
			
			long activityId = item.getId();
			long pageNo = 1;
			long pageCount = 500;
			int gksc = 0;
			long scqId = 0;
			
			CouponActivity couponActivity = new CouponActivity();
			couponActivity.setZbjlid(activityId);
			couponActivity.setQlx(2); //时长券
			
			List<CouponActivity> couponActivityList = couponActivityMapper.selectByEntity(couponActivity);
			if(null != couponActivityList && couponActivityList.size() > 0 ) {
				gksc = couponActivityList.get(0).getGksc();
				scqId = couponActivityList.get(0).getId();
			}

			GetUserBehaviorListResponseAPIV2 apiResponse = liveVideoService.getUserBehaviorDataList(activityId, pageNo, pageCount);
			List<UserBehaviorV2> userList = apiResponse.getResult().getData();

			
			
			if(null == userList || userList.size() == 0) {
				continue ;
			}
			
			LOG.error("直播间名称["+item.getName()+"],ID["+item.getId()+"]，同步的用户[" + userList.size() + "],开播时间["+item.getLiveTime()+"],开播时间["+gsrq+"],观看时长["+gksc+"]");
			
			processUserLiveTime(userList, userGkscMap, gsrq, item);
			long totalItemCount = apiResponse.getResult().getTotalItemCount();
			if (totalItemCount > (pageNo * pageCount)) {// 代表一页取完数据
				long countItemSize = apiResponse.getResult().getTotalItemCount();
				long pageSize = (long) Math.ceil((double) countItemSize / pageCount);
				for (int i = 1; i < pageSize; i++) {
					pageNo++;
					
					long startTime = System.currentTimeMillis();
					
					try {
						apiResponse = liveVideoService.getUserBehaviorDataList(activityId, pageNo, pageCount);
						
					}catch(Exception e) {
						e.printStackTrace();
						System.out.println("获取直播时长分页查询错误zbjid[" + activityId + "], pageNo[" + pageNo + "] ,错误信息: " + e.getMessage());
						apiResponse = liveVideoService.getUserBehaviorDataList(activityId, pageNo, pageCount);
					}
					
					
					userList = apiResponse.getResult().getData();
					
					if(null == userList || userList.size() == 0) { //如果分页查询异常，这里循环20次调用 每次间隔3秒
						int errorCount = 0;
						while(errorCount >= 20) {
							Thread.sleep(3000);
							try {
								apiResponse = liveVideoService.getUserBehaviorDataList(activityId, pageNo, pageCount);
								userList = apiResponse.getResult().getData();
								if(null != userList && userList.size() != 0) {
									break ;
								}
							}catch(Exception e) {
								LOG.error("循环同步观看时长异常" + e.getMessage());
								e.printStackTrace();
							}finally {
								errorCount++;
							}
						}
					}
					
					
					long endTime = System.currentTimeMillis();
					
					LOG.error("同步的直播间 耗时["+(endTime-startTime)+"] pageNo["+pageNo+"], pageSize["+pageSize+"], pageCount["+pageCount+"]");
					
					processUserLiveTime(userList, userGkscMap, gsrq, item);
					
				}
			}
			
			int insertCount = 0;
			
			// 数据入库
			for (String key : userGkscMap.keySet()) {
				LbsGkscDay lbsGkscDayItem = userGkscMap.get(key);

				if (null != lbsGkscDayItem.getId() && lbsGkscDayItem.getId() != 0) {
					lbsGkscDayService.update(lbsGkscDayItem);
				} else {
					lbsGkscDayService.insert(lbsGkscDayItem);
				}
				
				//完成后判断是否需要调用观看时长补发
				if(gksc != 0 && lbsGkscDayItem.getLivetime() >= gksc) {
					try {
						couponActivityNewService.receiveCouponScqBf(scqId, lbsGkscDayItem.getWcUserId());
					}catch (Exception e) {
						LOG.error("补发券异常 scqId["+scqId+"], WcUserId["+lbsGkscDayItem.getWcUserId()+"]");
						e.printStackTrace();
					}
				}
				
				insertCount++;
				if(insertCount % 200 == 0) {
					LOG.error("开始同步按天统计用户观看时长-数据入库 count["+insertCount+"]");
				}
			}
		}

		
	}
	
	
	

	private void processUserLiveTime(List<UserBehaviorV2> userList, Map<String, LbsGkscDay> userGkscMap, String gsrq, ListActivityAPIForm item) {
		
		if(null == userList || userList.size() == 0) {
			return ;
		}
		
		for (UserBehaviorV2 userBehaviorItem : userList) {
			String userIdStr = userBehaviorItem.getExternalUserId();

			//LOG.error("同步的用户ExternalUserId[" + userIdStr + "],WatchTime["+ userBehaviorItem.getWatchTime() +"]");
			
			if (null == userIdStr || "".equals(userIdStr)) {
				continue;
			}

			LbsGkscDay lbsGkscday = null;
			if (userGkscMap.containsKey(userIdStr)) {
				lbsGkscday = userGkscMap.get(userIdStr);
			} else {
				long wcUserId = Long.valueOf(userIdStr);
				Member member = memberMapper.selectById(wcUserId);
				if (null == member) { // 没有找到对应的会员
					continue;
				}
				lbsGkscday = initLbsGkscDay(member, wcUserId, gsrq, item);
				lbsGkscday.setLivetime(0);
				
				//ThumbUpNumber 点赞次数
				//CommentCounts 发送弹幕次数
				//UserName 火山观众昵称
				//UserId 火山观众ID
				userGkscMap.put(userIdStr, lbsGkscday);
			}

			
			//TODO 这里取消累加
			/*
			Integer reLiveTime = lbsGkscday.getLivetime();
d
			if (null == reLiveTime) {
				reLiveTime = new Integer(0);
			}
			Long sumTime = (reLiveTime + userBehaviorItem.getWatchTime());
			lbsGkscday.setLivetime(sumTime.intValue());*/
			lbsGkscday.setHsUserId(userBehaviorItem.getUserId());
			lbsGkscday.setHsUserName(userBehaviorItem.getUserName());
			lbsGkscday.setDzsl(userBehaviorItem.getThumbUpNumber());
			lbsGkscday.setDmsl(userBehaviorItem.getCommentCounts());
			lbsGkscday.setAccessTime(userBehaviorItem.getAccessTime());
			String userDevices = StringUtils.join(userBehaviorItem.getUserDevice(), ",");
			lbsGkscday.setUserDevice(userDevices);
			
			String jrsj = StringUtils.join(userBehaviorItem.getJoinAt(), ",");
			lbsGkscday.setJrsj(jrsj);
			
			String lksj = StringUtils.join(userBehaviorItem.getLeaveAt(), ",");
			lbsGkscday.setLksj(lksj);
			
			//TODO 这里火山有bug 使用 viewDuration
			//lbsGkscday.setLivetime(userBehaviorItem.getWatchTime().intValue());
			
			Long viewDuration = (userBehaviorItem.getViewDuration() / 60);
			lbsGkscday.setLivetime(viewDuration.intValue());
			

		}

	}

	private LbsGkscDay initLbsGkscDay(Member member, long wcUserId, String gsrq, ListActivityAPIForm item) {
		long zbjid = item.getId();
		String zbjmc = item.getName();
		QueryWrapper<LbsGkscDay> qw = new QueryWrapper();
		qw.eq("wc_user_id", wcUserId);
		qw.eq("gsrq", gsrq);
		qw.eq("zbjid", zbjid);

		LbsGkscDay lbsGkscday = lbsGkscDayMapper.selectOne(qw);
		if (null == lbsGkscday) {
			lbsGkscday = new LbsGkscDay();
			lbsGkscday.setGsrq(gsrq);
		}

		lbsGkscday.setZbjid(zbjid);
		lbsGkscday.setZbjmc(zbjmc);
		lbsGkscday.setDeptTzId(member.getDeptTzId());
		lbsGkscday.setDeptZbjId(member.getDeptZbjId());
		lbsGkscday.setDeptDpId(member.getDeptDpId());
		lbsGkscday.setSpreaduid(member.getSpreaduid());
		
		SysDept sysDept = sysDeptServiceImpl.getCacheSysDept(member.getDeptDpId());
		if(null != sysDept) {
			lbsGkscday.setDeptDpName(sysDept.getDeptName());
		}
		
		lbsGkscday.setWcUserId(wcUserId);
		lbsGkscday.setAvatar(member.getAvatar());
		lbsGkscday.setNickname(member.getNickname());
		return lbsGkscday;
	}

}
